import tensorflow as tf

"""
调用tf过程中，会出现一些红色提示：
2019-02-18 16:20:09.839405: I tensorflow/core/platform/cpu_feature_guard.cc:141] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2
这些红色是以为tensorflow对一些计算操作有硬件加速，而使用pip安装的版本有些加速功能是缺失的。但是这些缺失功能是不影响功能的。
要补全这些缺失的加速功能，需要用源码自行编译。
而如果不想要打印这些日志，可以把日志屏蔽掉。
"""
import os
os.environ['TF_CPP_MIN_LOG_LEVEL']='2'

def tensorflow_demo():
    """
    TensorFlow的基本结构
    :return:
    """
    # 原生python加法运算
    a = 2
    b = 3
    c = a + b
    print("普通加法运算的结果：",c)

    # TensorFlow实现加法运算
    a_t = tf.constant(2)
    b_t = tf.constant(3)
    c_t = a_t + b_t
    print("TensorFlow加法运算的结果：",c_t)
    # 这样拿不到结果，只拿到一个 Tensor("add:0", shape=(), dtype=int32)

    # 开启会话
    with tf.Session() as sess:
        c_t_value = sess.run(c_t)
        print("c_t_value:",c_t_value)

    return None

def graph_demo():
    # TensorFlow实现加法运算
    a_t = tf.constant(2)
    b_t = tf.constant(3)
    c_t = a_t + b_t
    print("TensorFlow加法运算的结果：", c_t)

    # 查看默认图
    # 方法1：调用方法
    default_g = tf.get_default_graph()
    print("default_g:",default_g)
    # 方法2：查看属性
    print("a_t的图属性：",a_t.graph)
    print("c_t的图属性：",c_t.graph)

    # 开启会话
    with tf.Session() as sess:
        c_t_value = sess.run(c_t)
        print("c_t_value:", c_t_value)
        print("sess的图属性：", sess.graph)
        #tensorboard可视化
        # 1 将图写入本地生成events文件
        tf.summary.FileWriter(".",graph=sess.graph)

    # 自定义图
    new_g = tf.Graph()
    # 在自己的图中定义数据和操作：
    with new_g.as_default():
        a_new = tf.constant(20)
        b_new = tf.constant(30)
        c_new = a_new+b_new
        print("c_new : ",c_new)
    # 开启会话 - 使用自定义图
    with tf.Session(graph=new_g) as new_sess:
        c_new_value = new_sess.run(c_new)
        print("c_new_value : ",c_new_value)
        print("c_new的图属性 ：",c_new.graph)

    return None

def tensor_demo():
    """
    张量的演示
    :return:
    """
    tensor1 = tf.constant(4.0)
    tensor2 = tf.constant([1,2,3,4])
    linear_squares = tf.constant([[4],[9],[16],[25]],dtype=tf.int32)

    print("tensor1: ",tensor1)
    print("tensor2: ",tensor2)
    print("linear_squares: ",linear_squares)
    return None

def var_demo():
    """
    变量演示
    :return:
    """
    #修改命名空间
    with tf.variable_scope("scope1"):
        a = tf.Variable(initial_value=30)
        b = tf.Variable(initial_value=20)
    with tf.variable_scope("scope2"):
        c = tf.add(a,b)
    print("a: ",a)
    print("b: ",b)
    print("c: ",c)

    # 所有变量需要手动调用进行初始化
    init = tf.global_variables_initializer()

    with tf.Session() as sess:
        sess.run(init)
        a_new,b_new,c_new = sess.run([a,b,c])
        print("a_new : ",a_new)
        print("b_new : ",b_new)
        print("c_new : ",c_new)

    return None

def linear_regression():
    """
        线性回归例子
    :return:
    """
    # 1） 准备数据
    # 构造一组 y = 0.8*x + 0.7的数据作为数据集，测试梯度下降逼近的结果。
    x = tf.random_normal(shape=[100,1])
    y_true=tf.matmul(x,[[0.8]])+0.7
    # 2） 构造模型
    # 定义模型参数 用 变量
    # 构造初始模型参数，测试梯度下降的逼近结果。
    weights = tf.Variable(initial_value=tf.random_normal(shape=[1,1]))
    bias = tf.Variable(initial_value=tf.random_normal(shape=[1,1]),trainable=False)
    y_predict = tf.matmul(x,weights)+bias
    # 3） 构造损失函数
    error = tf.reduce_mean(tf.square(y_predict - y_true))
    # 4） 优化损失
    optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.01).minimize(error)

    init = tf.global_variables_initializer();
    #开启会话
    with tf.Session() as sess:
        sess.run(init)
        # 查看初始化模型参数之后的值
        print("训练前模型参数： weights => %f, 偏置 => %f,损失为 => %f " %(weights.eval(),bias.eval(),error.eval()))
        # 开始训练
        for i in range(100):
            """
                进行一次梯度下降训练。只需要执行最后一个tensor。相关联的tensor也会跟着计算出来。
                一般能看到，一次梯度下降训练，损失函数有可能还会增加。但是经过多次训练后，损失函数还是下降很明显的。
                最终逼近的结果比较理想。1000次后，损失函数都能逼近到0
            """
            sess.run(optimizer)
            #保存模型
            #saver = tf.train.Saver(var_list=[weights,bias] ,max_to_keep=5)
            # 加载模型
            #saver.save(sess,"./model/linear.ckpt")
            #saver.restore(sess,'./model/linear.ckpt')
        # 查看训练后的模型参数
        print("训练后模型参数： weights => %f, 偏置 => %f,损失为 => %f " % (weights.eval(), bias.eval(), error.eval()))
    return None

if __name__ == "__main__":
    #TensorFlow的基本结构
    #tensorflow_demo()
    # 图演示
    #graph_demo()
    # 张量演示
    #tensor_demo()
    # 变量演示
    # var_demo()
    # TensorFlow实现的梯度下降
    linear_regression()